package com.base.cn.platform.os.service.user.integral;

import com.base.cn.platform.os.common.RedissonQueue;
import com.base.cn.platform.os.common.constants.CacheConstants;
import com.base.cn.platform.os.common.j2cache.CustomCacheChannel;
import com.base.cn.platform.os.common.j2cache.J2CacheRegion;
import com.base.cn.platform.os.common.mybatis.BaseBiz;
import com.base.cn.platform.os.common.redisson.ParamEntity;
import com.base.cn.platform.os.common.redisson.RedissonConstants;
import com.base.cn.platform.os.common.utils.DataUtil;
import com.base.cn.platform.os.common.utils.DateUtils;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.common.utils.action.ActionKey;
import com.base.cn.platform.os.dao.user.integral.CusUserIntegralDao;
import com.base.cn.platform.os.entity.course.cou.record.CourseLearnFlow;
import com.base.cn.platform.os.entity.exam.record.ExamRecord;
import com.base.cn.platform.os.entity.qa.question.QaQuestion;
import com.base.cn.platform.os.entity.user.integral.CusUserIntegral;
import com.base.cn.platform.os.entity.user.integral.CusUserIntegralRecord;
import com.base.cn.platform.os.entity.user.integral.IntegralRule;
import com.base.cn.platform.os.entity.user.loginLog.CusUserLoginLog;
import com.base.cn.platform.os.service.course.cou.record.CourseLearnFlowService;
import com.base.cn.platform.os.service.course.qa.question.QaQuestionService;
import com.base.cn.platform.os.service.exam.record.ExamRecordService;
import com.base.cn.platform.os.service.user.loginLog.CusUserLoginLogBiz;
import net.oschina.j2cache.CacheObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户积分Biz
 */
@Service
public class CusUserIntegralBiz extends BaseBiz<CusUserIntegral,CusUserIntegralDao> {

    @Autowired
    private CusUserIntegralRecordBiz cusUserIntegralRecordBiz;
    @Autowired
    private CusUserLoginLogBiz cusUserLoginLogBiz;
    @Autowired
    private ExamRecordService examRecordService;
    @Autowired
    private IntegralRuleBiz integralRuleBiz;
    @Autowired
    private QaQuestionService qaQuestionService;
    @Autowired
    private CourseLearnFlowService courseLearnFlowService;
    @Autowired
    private CustomCacheChannel customCacheChannel;
    @Autowired
    private RedissonQueue redissonQueue;

    @Async
    public void   inviterDealWith(String inviterKey,BigDecimal beInviterId){
        if(StringUtils.isNotEmpty(inviterKey)){
            String[] s = inviterKey.split("_");
            if(s.length==2){
                String s1 = s[1];
                addUserIntegralData(ActionKey.REGISTER,new BigDecimal(s1),beInviterId,0,2);
            }else{
                return;
            }
        }else{
            return;
        }
    }
    /**
     * 获取用户积分Sql
     * @param cusUserIntegral
     * @return
     */
    public String whereSql(CusUserIntegral cusUserIntegral){
        String where=" 1=1 ";
        if(ObjectUtils.isNotEmpty(cusUserIntegral)){
            if(DataUtil.idIsNotNull(cusUserIntegral.getUserId())){
                where += " and userId = "+cusUserIntegral.getUserId();
            }
        }
        return where;
    }

    /**
     * 根据用户Id 搜索用户积分
     * @param userId
     * @return
     */
    public CusUserIntegral queryUserIntegralByUserId(BigDecimal userId){
        if(DataUtil.idIsNotNull(userId)){
            CusUserIntegral cusUserIntegral = new CusUserIntegral();
            cusUserIntegral.setUserId(userId);
            String where = whereSql(cusUserIntegral);
            List<CusUserIntegral> userIntegrals = this.find(where,null,null);
            CusUserIntegral  userIntegral = null;
            if(ObjectUtils.isNotEmpty(userIntegrals)){
                userIntegral =  userIntegrals.get(0);
            }else{
                userIntegral = new CusUserIntegral();
                userIntegral.setUserId(userId);
                userIntegral.setCurrentScore(0);
                userIntegral.setTotalScore(0);
                userIntegral.setConsumeScore(0);
                userIntegral.setProtectScore(0);
                this.save(userIntegral);
            }
            return userIntegral;
        }
        return null;
    }

    /**
     * Ids搜索积分账户
     * @param userIds
     * @return
     */
    public List<CusUserIntegral> queryUserIntegralByUserIds(String userIds){
        List<CusUserIntegral> userIntegrals = new ArrayList<>();
        if (StringUtils.isNotEmpty(userIds)){
            userIntegrals = this.find(" userId in ("+userIds+")",null,null);
        }
        return userIntegrals;
    }

    /**
     * 添加用户积分
     * @param actionKey 动作KEY
     * @param userId 用户ID
     * @param recordType 记录类型，1消耗，2是添加
     */
    @Async
    @Transactional(rollbackFor =  IllegalArgumentException.class)
    public void addUserIntegralData(String actionKey,
                                    BigDecimal userId,
                                    BigDecimal otherId,
                                    int score,
                                    int recordType){
        if(StringUtils.isNotEmpty(actionKey)){
            actionKey = actionKey.trim();

            // 计算保护期时间
            Long minute=this.getProtectTime();
            // 注册获取积分
            if (ActionKey.REGISTER.equals(actionKey)) {
                IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
                registeredAddUserIntegral(integralRule, recordType, userId, minute, otherId);
            }

            //后台赠送积分
            if (ActionKey.GIFT.equals(actionKey)) {
                IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
                cusUserIntegralRecordBiz.addUserIntegralRecord(score, 2, "后台赠送",integralRule.getKey(), integralRule.getId(), userId,null);
            }

            // 签到赠送积分   支付成功赠送积分
            if (ActionKey.SIGNIN.equals(actionKey)||ActionKey.PAYSUCCESS.equals(actionKey)) {
                IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
                commonAddUserIntegral(integralRule, recordType, userId, minute);
            }

            // 登录获取
            if (ActionKey.LOGIN.equals(actionKey)) {
                this.addLoginIntegral(userId);
            }
            // 发表话题
            if (ActionKey.TOPIC.equals(actionKey)) {
                this.addAnswerIntegral(userId,minute,actionKey);
            }
            if (ActionKey.ANSWER.equals(actionKey)) {
                this.addAnswerIntegral(userId,minute,actionKey);
            }
            // 积分兑换商品
            if (ActionKey.GOODS.equals(actionKey)) {
                cusUserIntegralRecordBiz.addUserIntegralRecord(score, recordType, "兑换商品", actionKey,null, userId,null);
            }
            // 积分兑换现金
            if (ActionKey.MONEY.equals(actionKey)) {
                cusUserIntegralRecordBiz.addUserIntegralRecord(score, recordType, "兑换现金", actionKey,null, userId,null);
            }
            // 做题获取积分
            if (ActionKey.EXERCISE.equals(actionKey)) {
                this.addExamIntegral(userId, actionKey, minute);
            }
            // 看课获取积分
            if (ActionKey.COURSE.equals(actionKey)) {
                this.addCourseIntegral(userId, minute, actionKey, otherId);
            }
            // 提问获取积分
            if (ActionKey.QUESTION.equals(actionKey)) {
                this.addQuestionIntegral(actionKey,userId,minute);
            }

            //分享获取
            if (ActionKey.SHARE.equals(actionKey)) {
                this.addShareIntegral(actionKey,userId,minute,otherId);
            }
        }
    }

    /**
     * 分享获取积分
     * @param actionKey
     * @param userId
     * @param minute
     * @param otherId
     */
    private void addShareIntegral(String actionKey, BigDecimal userId, Long minute, BigDecimal otherId) {
        IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
        TreeMap<String, String> ruleMap = integralRule.getContextTreeMap();
        Integer max = Integer.valueOf(ruleMap.get("max"));

        BigDecimal currentDayTotalScore = this.getCurrentDayTotalScoreByKey(userId, actionKey);
        if (ObjectUtils.isEmpty(otherId) && currentDayTotalScore.compareTo(new BigDecimal(max)) == 1) {
            return;
        }
        Integer score=null;
        if (ObjectUtils.isNotEmpty(otherId)) {
            score = Integer.valueOf(ruleMap.get("shareSuccess"));
        }else{
            score = Integer.valueOf(ruleMap.get("shareScore"));
        }
        cusUserIntegralRecordBiz.addUserIntegralRecord(score, 2, integralRule.getDescription(), actionKey, integralRule.getId(), userId,null);
        putProtectScore(score, userId, minute);

    }

    /**
     * 获取积分保护期时间
     * @return
     */
    private Long getProtectTime() {
        IntegralRule protectTimeRule = integralRuleBiz.getIntegralRuleByKey("PROTECT");
        Integer day = Integer.valueOf(protectTimeRule.getContextTreeMap().get("day"));
        Long minute = DateUtils.getMinutesByDays(day);
        return minute;
    }

    /**
     * 提问获取积分
     * @param actionKey 规则id
     * @param userId  用户id
     * @param minute  放入保护期时间
     */
    private void addQuestionIntegral(String actionKey, BigDecimal userId, Long minute) {
        IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
        List<Map<String, String>> ruleList = integralRule.getContextList();
        Integer max = Integer.valueOf(ruleList.get(0).get("max"));
        BigDecimal currentDayTotalScoreByKey = getCurrentDayTotalScoreByKey(userId, actionKey);
        if (currentDayTotalScoreByKey.compareTo(new BigDecimal(max)) == -1) {
            List<QaQuestion> questionList = qaQuestionService.findQaQuestionByUserId(userId);
            if (ObjectUtils.isEmpty(questionList)) {
                questionList = new ArrayList<>();
            }
            int qaCount = questionList.size();
            int index=0;
            for (int i = 0; i < ruleList.size(); i++) {
                Integer unit = Integer.valueOf(ruleList.get(i).get("unit"));
                if (qaCount == unit) {
                    index=i;
                    break;
                }else if(qaCount<unit){
                    index=i-1;
                    break;
                }else{
                    index=i;
                }
            }
            Map<String, String> ruleMap = null;
            if (index >= 0) {
                ruleMap= ruleList.get(index);
                Integer score = Integer.valueOf(ruleMap.get("score"));
                cusUserIntegralRecordBiz.addUserIntegralRecord(score, 2, integralRule.getDescription(), integralRule.getKey(),integralRule.getId(), userId,null);
                this.putProtectScore(score,userId,minute);
            }
        }
    }


    /**
     * 公共添加积分记录
     * @param integralRule 积分规则
     * @param recordType
     * @param userId
     * @param minute
     */
    public void registeredAddUserIntegral(IntegralRule integralRule,Integer recordType,BigDecimal userId,Long minute, BigDecimal otherId) {
        // 获取积分规则
        Integer score = Integer.valueOf(integralRule.getContextTreeMap().get("score"));
        // 添加积分流水记录与用户记录
        cusUserIntegralRecordBiz.addUserIntegralRecord(score, recordType, integralRule.getDescription(), integralRule.getKey(),integralRule.getId(), userId,otherId);
        // 将获取的积分放入延迟队列
        if (minute > 0) {
            if (!ActionKey.REGISTER.equals(integralRule.getKey())) {
                this.putProtectScore(score, userId, minute);
            }
        }
    }

    /**
     * 公共添加积分记录
     * @param integralRule 积分规则
     * @param recordType
     * @param userId
     * @param minute
     */
    public void commonAddUserIntegral(IntegralRule integralRule,Integer recordType,BigDecimal userId,Long minute) {
        // 获取积分规则
        Integer score = Integer.valueOf(integralRule.getContextTreeMap().get("score"));
        // 添加积分流水记录与用户记录
        cusUserIntegralRecordBiz.addUserIntegralRecord(score, recordType, integralRule.getDescription(), integralRule.getKey(),integralRule.getId(), userId,null);
        // 将获取的积分放入延迟队列
        if (minute > 0) {
            if (!ActionKey.REGISTER.equals(integralRule.getKey())) {
                this.putProtectScore(score, userId, minute);
            }
        }
    }


    /**
     * 修改用户积分统计记录
     * @param score  获取/消耗 积分
     * @param recordType  1 消耗  2 获取
     * @param userId 用户id
     */
    public CusUserIntegral updateUserIntegral(Integer score, Integer recordType, BigDecimal userId,String actionKey) {
        CusUserIntegral cusUserIntegral = this.findOne(" userId= " + userId, null);
        if (ObjectUtils.isEmpty(cusUserIntegral)) {
            cusUserIntegral = new CusUserIntegral();
            cusUserIntegral.setUserId(userId);
            cusUserIntegral.setCurrentScore(0);
            if (!ActionKey.LOGIN.equals(actionKey) && !ActionKey.REGISTER.equals(actionKey) && !ActionKey.GIFT.equals(actionKey)) {
                cusUserIntegral.setProtectScore(score); // 获取积分加入保护期
            } else {
                cusUserIntegral.setCurrentScore(score);
            }
            cusUserIntegral.setConsumeScore(0);
            cusUserIntegral.setTotalScore(score);
            this.save(cusUserIntegral);

        }else{
            CusUserIntegral cusUserIntegralNew = new CusUserIntegral();
            cusUserIntegralNew.setId(cusUserIntegral.getId());
            if (recordType==1) { // 消耗积分
                cusUserIntegralNew.setCurrentScore(cusUserIntegral.getCurrentScore()-score);
                cusUserIntegralNew.setConsumeScore(cusUserIntegral.getConsumeScore() + score);
            } else if (recordType == 2) { // 获取积分
                // 登录、注册 获取积分不需要放入保护期
                if (!ActionKey.LOGIN.equals(actionKey) && !ActionKey.REGISTER.equals(actionKey)&& !ActionKey.GIFT.equals(actionKey)) {
                    cusUserIntegralNew.setProtectScore(cusUserIntegral.getProtectScore()+score); // 获取积分加入保护期
                }else{
                    cusUserIntegralNew.setCurrentScore(cusUserIntegral.getCurrentScore()+score);
                }

                cusUserIntegralNew.setTotalScore(cusUserIntegral.getTotalScore() + score);//  统计总共获取 当延迟队列执行时不必再加
            }
            this.updateById(cusUserIntegralNew, null);
        }
        return cusUserIntegral;
    }


    /**
     * 将保护期积分放入延迟队列
     */
    public void putProtectScore(Integer score,BigDecimal userId,Long  minute) {
        ParamEntity paramEntity = new ParamEntity();
        paramEntity.setType(RedissonConstants.INTEGRAL_QUEUE);
        Map<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        map.put("protectScore", score);
        paramEntity.setMap(map);
        redissonQueue.putQueue(paramEntity, minute, false);
    }


    /**
     * 添加用户登录积分
     * @param userId 用户id
     */
    private void addLoginIntegral(BigDecimal userId) {
        // 判断是否是每天第一次登录
        List<CusUserLoginLog> cusUserLoginLogList = cusUserLoginLogBiz.find(" TO_DAYS(createTime) =TO_DAYS(NOW()) and userId= " + userId, null, null);
        if (cusUserLoginLogList.size() == 1) {
            CacheObject cacheObject = customCacheChannel.get(J2CacheRegion.THIRTY_SIX_HOURS_REGION.toString(), CacheConstants.LOGIN_COUNT+userId);
            Integer loginCount= (Integer) cacheObject.getValue();
            IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(ActionKey.LOGIN);
            List<Map<String, String>> ruleList = integralRule.getContextList();
            int index=0;
            Map<String, String> ruleMap = null;
            for (int i = 0; i < ruleList.size(); i++) {
                Integer day = Integer.valueOf(ruleList.get(i).get("unit"));
                if (loginCount==day) {
                    index = i;
                    break;
                } else if (loginCount < day) {
                    index = i-1;
                    break;
                } else {
                    index=i;
                }
            }
            if (index >= 0) {
                ruleMap= ruleList.get(index);
                Integer score = Integer.valueOf(ruleMap.get("score"));
                cusUserIntegralRecordBiz.addUserIntegralRecord(score, 2, integralRule.getDescription(), integralRule.getKey(),integralRule.getId(), userId,null);

            }
        }
    }


    /**
     * 添加回答,
     * @param userId 用户id
     * @param minute 放入积分保护期时间
     */
    private void addAnswerIntegral(BigDecimal userId, Long minute,String actionKey) {
        // 查询学员当天问答获取的
        IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
        BigDecimal score = getCurrentDayTotalScoreByKey(userId, actionKey);
        Map<String, String> ruleMap = integralRule.getContextTreeMap();
        Integer currentDayMaxScore = Integer.valueOf(ruleMap.get("max"));
        if (score.compareTo(new BigDecimal(currentDayMaxScore)) == -1) {
            commonAddUserIntegral(integralRule, 2, userId, minute);
        }
    }


    /**
     * 获取用户当某个规则累计获取的积分
     * @param userId 用户id
     * @param actionKey 规则key
     * @return
     */
    private BigDecimal getCurrentDayTotalScoreByKey(BigDecimal userId,String actionKey) {
        BigDecimal score = cusUserIntegralRecordBiz.sum("score", " createTime =NOW() and userId= " + userId + " and recordType=2 and  ruleKey='" + actionKey + "' ");
        if (ObjectUtils.isEmpty(score)) {
            score = BigDecimal.ZERO;
        }
        return score;
    }


    /**
     * 做题获取积分
     */
    private void addExamIntegral(BigDecimal userId,String actionKey,Long minute){
        // 获取规则
        IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
        List<Map<String, String>> ruleList = integralRule.getContextList();
        // 判断当天做题获取积分是否达到最大值
        BigDecimal max = new BigDecimal(ruleList.get(0).get("max"));
        BigDecimal currentDayTotalScore = getCurrentDayTotalScoreByKey(userId, actionKey);
        if (currentDayTotalScore.compareTo(max)==-1) {
            // 获取试题数量
            Map<String, Object> map = new HashMap<>();
            map.put("userId", userId);
//            map.put("useType", 1);
            List<ExamRecord> examRecordList = examRecordService.findExamRecord(map);
            if (ObjectUtils.isEmpty(examRecordList)) {
                examRecordList = new ArrayList<>();
            }
            int qaCount = examRecordList.stream().mapToInt(e -> e.getQuestionCount()).sum();
            int index=0;
            for (int i = 0; i < ruleList.size(); i++) {
                Integer unit = Integer.valueOf(ruleList.get(i).get("unit"));
                if (qaCount == unit) {
                    index=i;
                    break;
                }else if(qaCount<unit){
                    index=i-1;
                    break;
                }else{
                    index=i;
                }
            }
            Map<String, String> ruleMap = null;
            if (index >= 0) {
                ruleMap= ruleList.get(index);
                Integer score = Integer.valueOf(ruleMap.get("score"));
                cusUserIntegralRecordBiz.addUserIntegralRecord(score, 2, integralRule.getDescription(), integralRule.getKey(),integralRule.getId(), userId,null);
                this.putProtectScore(score,userId,minute);
            }
        }
    }


    /**
     * 看课获取积分 （每看一节赠送一次 每节最多看三次）
     * @param userId 用户id
     * @param minute 保护期时长
     * @param actionKey 规则key
     */
    private void addCourseIntegral(BigDecimal userId,Long minute,String actionKey,BigDecimal otherId) {
        IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
        TreeMap<String, String> ruleMap = integralRule.getContextTreeMap();
        Integer score = Integer.valueOf(ruleMap.get("score"));
        List<CourseLearnFlow> courseLearnFlowList = courseLearnFlowService.findCourseLearnFlowByMaterialId(otherId);
        if (ObjectUtils.isNotEmpty(courseLearnFlowList)) {
            if (courseLearnFlowList.size() > 3) {
                return;
            }
        }
        this.commonAddUserIntegral(integralRule, 2, userId, minute);


    }

    /**
     * 批量添加用户积分（围观问题）
     * @param userIdList 用户id集合
     * @param actionKey
     */
    @Async
    public void batchAddUserIntegral(List<BigDecimal> userIdList, String actionKey) {
        IntegralRule integralRule = integralRuleBiz.getIntegralRuleByKey(actionKey);
        TreeMap<String, String> ruleMap = integralRule.getContextTreeMap();
        String userIds = userIdList.stream().map(e -> String.valueOf(e)).collect(Collectors.joining(","));
        List<CusUserIntegralRecord> cusUserIntegralRecordList = cusUserIntegralRecordBiz.find(" userId IN(" + userIds + ") and TO_DAYS(createTime) =TO_DAYS(NOW()) AND ruleKey='" + actionKey + "' ", null, null);
        Map<BigDecimal, List<CusUserIntegralRecord>> recordMap = cusUserIntegralRecordList.stream().collect(Collectors.groupingBy(e -> e.getUserId()));
        Integer max = Integer.valueOf(ruleMap.get("max"));
        Integer score = Integer.valueOf(ruleMap.get("score"));
        CusUserIntegralRecord lastCusUserIntegralRecord = cusUserIntegralRecordBiz.findOne(" 1=1 order by createTime desc  ", null);
        Integer totalScore = lastCusUserIntegralRecord.getTotalScore();
        Integer useScore = lastCusUserIntegralRecord.getUseScore();
        List<CusUserIntegralRecord> newRecordList = new ArrayList<>();
        List<CusUserIntegral> cusUserIntegralList = this.find("userId IN (" + userIds + ")", null, null);
        Map<BigDecimal,CusUserIntegral> userIntegralMap = cusUserIntegralList.stream().collect(Collectors.toMap(e -> e.getUserId(),e->e));
        List<CusUserIntegral> newCususerIntegralList = new ArrayList<>();
        Long protectTime = this.getProtectTime();
        for (int i = 0; i < userIdList.size(); i++) {
            totalScore =totalScore+ score;
            useScore = useScore + score;
            BigDecimal userId = userIdList.get(i);
            List<CusUserIntegralRecord> current = recordMap.get(userId);
            if (ObjectUtils.isEmpty(current)) {
                current = new ArrayList<>();
            }
            CusUserIntegral cusUserIntegral = userIntegralMap.get(userId);
            int getScore = current.stream().mapToInt(f -> f.getScore()).sum();
            // 当天超过此规则的最大获取积分数跳过
            if (ObjectUtils.isNotEmpty(current)&&(getScore > max)) {
                continue;
            }else{

                // 修改用户积分账户积分
                cusUserIntegral.setProtectScore(cusUserIntegral.getProtectScore() + score);
                cusUserIntegral.setTotalScore(cusUserIntegral.getTotalScore() + score);
                newCususerIntegralList.add(cusUserIntegral);

                CusUserIntegralRecord cusUserIntegralRecord = cusUserIntegralRecordBiz.createIntegralRecord(score,userIdList.get(i), integralRule, totalScore, useScore, lastCusUserIntegralRecord.getConsumeScore(),cusUserIntegral.getCurrentScore());
                newRecordList.add(cusUserIntegralRecord);
                this.putProtectScore(score,userId,protectTime);
            }
        }
        if (ObjectUtils.isNotEmpty(newRecordList)) {
            this.updateBatch(newCususerIntegralList);
            cusUserIntegralRecordBiz.batchSave(newRecordList);
        }

    }
}
